From: Jan Beulich Date: Tue, 11 Oct 2022 12:56:29 +0000 (+0200) Subject: gnttab: correct locking on transitive grant copy error path X-Git-Tag: archive/raspbian/4.16.2+90-g0d39a6d1ae-1+rpi1^2~28^2~74 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=32cb81501c8b858fe9a451650804ec3024a8b364;p=xen.git gnttab: correct locking on transitive grant copy error path While the comment next to the lock dropping in preparation of recursively calling acquire_grant_for_copy() mistakenly talks about the rd == td case (excluded a few lines further up), the same concerns apply to the calling of release_grant_for_copy() on a subsequent error path. This is CVE-2022-33748 / XSA-411. Fixes: ad48fb963dbf ("gnttab: fix transitive grant handling") Signed-off-by: Jan Beulich master commit: 6e3aab858eef614a21a782a3b73acc88e74690ea master date: 2022-10-11 14:29:30 +0200 --- diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c index 4c742cd8fe..d8ca645b96 100644 --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -2613,9 +2613,8 @@ acquire_grant_for_copy( trans_domid); /* - * acquire_grant_for_copy() could take the lock on the - * remote table (if rd == td), so we have to drop the lock - * here and reacquire. + * acquire_grant_for_copy() will take the lock on the remote table, + * so we have to drop the lock here and reacquire. */ active_entry_release(act); grant_read_unlock(rgt); @@ -2652,11 +2651,25 @@ acquire_grant_for_copy( act->trans_gref != trans_gref || !act->is_sub_page)) ) { + /* + * Like above for acquire_grant_for_copy() we need to drop and then + * re-acquire the locks here to prevent lock order inversion issues. + * Unlike for acquire_grant_for_copy() we don't need to re-check + * anything, as release_grant_for_copy() doesn't depend on the grant + * table entry: It only updates internal state and the status flags. + */ + active_entry_release(act); + grant_read_unlock(rgt); + release_grant_for_copy(td, trans_gref, readonly); rcu_unlock_domain(td); + + grant_read_lock(rgt); + act = active_entry_acquire(rgt, gref); reduce_status_for_pin(rd, act, status, readonly); active_entry_release(act); grant_read_unlock(rgt); + put_page(*page); *page = NULL; return ERESTART;